package stardust.core.java.thread;


import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import stardust.core.java.thread.ProxyRunnable.ProxyRunnableCallback;


public class FixedThreadPool implements ProxyRunnableCallback
{
  
  private final Object LOCK = new Object();
  
  protected String threadPoolName;
  protected int maxThreadCount;
  protected int maxWaitJobCount;
  
  protected LinkedList<Runnable> jobQueue = new LinkedList<Runnable>();
  protected LinkedList<ProxyRunnable> idleQueue;
  protected LinkedList<ProxyRunnable> workQueue;
  
  private List<Thread> threads;
  private boolean shutdownFlag;
  
  public FixedThreadPool(String threadPoolName, int maxThreadCount, int maxWaitJobCount)
  {
    this.threadPoolName = threadPoolName;
    this.maxThreadCount = maxThreadCount;
    this.maxWaitJobCount = maxWaitJobCount;
    
    this.initiate();
  }
  
  private void initiate()
  {
    this.shutdownFlag = false;
    
    this.idleQueue = new LinkedList<ProxyRunnable>();
    this.workQueue = new LinkedList<ProxyRunnable>();
    
    this.threads = new ArrayList<Thread>();
    
    for (int i = 0; i < this.maxThreadCount; i++)
    {
      ProxyRunnable proxyRunnable = new ProxyRunnable(this);
      Thread thread = new Thread(proxyRunnable);
      
      thread.setDaemon(true);
      thread.start();
      
      this.idleQueue.addFirst(proxyRunnable);
      this.threads.add(thread);
    }
  }
  
  public List<Runnable> shutdown() throws InterruptedException
  {
    this.shutdownFlag = true;
    
    for (Thread i : this.threads)
    {
      i.interrupt();
    }
    
    for (Thread i : this.threads)
    {
      i.join();
    }
    
    this.idleQueue.clear();
    this.workQueue.clear();
    
    return this.jobQueue;
  }
  
  public boolean run(Runnable runnable)
  {
    if (this.shutdownFlag)
    {
      return false;
    }
    
    synchronized (this.LOCK)
    {
      if (this.jobQueue.size() + 1 > this.maxWaitJobCount)
      {
        return false;
      }

      this.jobQueue.addFirst(runnable);
      this.LOCK.notify(); // 唤醒某个线程开始执行任务。
      
      return true;
    }
  }
  
  public Runnable onStart(ProxyRunnable proxy) throws InterruptedException
  {
    synchronized (this.LOCK)
    {
      while (this.jobQueue.isEmpty())
      {
        this.LOCK.wait(); // 如果当前没有可执行的任务将暂停线程并等待外部通知。
      }
      
      this.idleQueue.remove(proxy);
      this.workQueue.addFirst(proxy);
      return this.jobQueue.removeLast();
    }
  }

  public void onStop(ProxyRunnable proxy, Throwable exception)
  {
    synchronized (this.LOCK)
    {
      this.workQueue.remove(proxy);
      this.idleQueue.addFirst(proxy);
    }
  }

}
